package com.easycoding.ums.security.shiro.realm;


import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.easycoding.ums.security.shiro.SessionKey;
import com.easycoding.ums.security.shiro.expand.UserVerifyExpandOperator;
import com.easycoding.ums.security.shiro.token.CaptchaUsernamePasswordToken;
import com.easycoding.ums.system.bo.UserTicket;
import com.easycoding.ums.system.entity.Permission;
import com.easycoding.ums.system.entity.Role;
import com.easycoding.ums.system.entity.User;
import com.easycoding.ums.system.service.UserService;
import com.easycoding.framework.exception.SecurityException;
import com.easycoding.framework.web.WebContextHelper;


/**
 * 通过数据库权限认证
 * @author Wangjk
 * @Version 1.0
 * @Date 2013-4-4
 */
public class DbRealm extends AuthorizingRealm implements ApplicationContextAware{
	
	protected final Log logger = LogFactory.getLog(getClass());
	
	private static ApplicationContext applicationContext;
	
	/**
	 * 用户服务
	 */
	@Resource(name = "umsUserService")
	private UserService userService;
	
	/**
	 * 是否有验证码
	 */
	private boolean captcha;
	
	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		//String username = (String)principals.fromRealm(getName()).iterator().next();
		UserTicket userTicket = (UserTicket)SecurityUtils.getSubject().getSession().getAttribute(SessionKey.USER);
		if (userTicket != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			//角色
			if(userTicket.getRoles() != null && !userTicket.getRoles().isEmpty()){
				for(Role role : userTicket.getRoles()){
					info.addRole(role.getName());
				}
			}
			//权限
			if( userTicket.getPermissions() != null && !userTicket.getPermissions().isEmpty()){
				for(Permission permission : userTicket.getPermissions()){
					info.addStringPermission(permission.getEname());
				}
			}
			return info;
		} else {
			return null;
		}
	}

	/**
	 * 认证回调函数,登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		CaptchaUsernamePasswordToken token = (CaptchaUsernamePasswordToken) authcToken;
		String userName = token.getUsername();
		String password = new String(token.getPassword());
		//验证码 验证
		if(this.captcha){
//			Boolean isResponseCorrect =Boolean.FALSE;
			String captcha = token.getCaptcha().toUpperCase();
			
			String input = (String)WebContextHelper.getSessionVal("captcha");
			if(StringUtils.isEmpty(input) || !input.equals(captcha)){
				SecurityUtils.getSubject().getSession().setAttribute(SessionKey.LOGIN_FAIL, "验证码错误!");
				return null;
			}
				
//			String captchaId = SecurityUtils.getSubject().getSession().getId().toString();
//			isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId,captcha);
//			if (!isResponseCorrect) {
//				SecurityUtils.getSubject().getSession().setAttribute(SessionKey.LOGIN_FAIL, "验证码错误!");
//				return null;
//			}
		}
		try{
			//用户名密码验证
			User user = userService.verifyUser(userName, password);
			UserTicket userTicket = userService.findByUserAccount(user.getAccount());
			SecurityUtils.getSubject().getSession().setAttribute(SessionKey.USER,userTicket);
			if(!this.customVerify(authcToken)){
				throw new SecurityException("验证失败");
			}
		}
		catch(SecurityException e){
			if(logger.isInfoEnabled())
				logger.info("登录失败",e);
			SecurityUtils.getSubject().getSession().setAttribute(SessionKey.LOGIN_FAIL, "用户名或密码错误!");
			return null;
		}
		catch(Exception e){
			if(logger.isInfoEnabled())
				logger.info("登录失败",e);
			SecurityUtils.getSubject().getSession().setAttribute(SessionKey.LOGIN_FAIL, "登录失败!");
			return null;
		}
		return new SimpleAuthenticationInfo(userName,password,getName());
	}
	
	/**
	 * 自定义用户验证
	 * @param authcToken
	 * @return 返回true 代表验证通过，返回false 代表验证失败
	 */
	private boolean customVerify(AuthenticationToken authcToken){
		// 按类型获取上下文中的对象  
        Map<String, UserVerifyExpandOperator> map = applicationContext.getBeansOfType(UserVerifyExpandOperator.class, true, true);  
		for (UserVerifyExpandOperator operator : map.values()) {  
	    	if(!operator.verify(authcToken))
	    		return false;
		}  
		return true;
	}

	public boolean isCaptcha() {
		return captcha;
	}

	public void setCaptcha(boolean captcha) {
		this.captcha = captcha;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		DbRealm.applicationContext = applicationContext;
	}
}
